import wx, random, math

#TODO


# Orphan note finder (create a notespace of). Keeping notes tider is something i am keen on doing.

# Need to show if all child notes are out or not - by colour, outline, icon etc.

# When a note is expanded to show child notes, why to existing child notes move? they shouldnt  

# Note sorting, want to be able to sort arround any given note!

# Make a tag which bars a note from tomboyview (or tomspace) e.g. noviewtomspace

# Drop the whole scaling thing, and just change the font size, let widgets sort themselves out?

class NoteSpace():
    """Class to hold notes in"""
    def __init__(self, tomboy):
        self.tomboy = tomboy
        self.notes = {}
        self.drawEnable = False
    
    def clearNotes(self):
        self.notes = {}
    
    def addNote(self, title):
        noteID = self.tomboy.FindNote(title)
        self.notes[noteID] = VisualNote(self, noteID)
    
    def addNotes(self, tag=None, childrenOf=None):
        if tag != None:
            tomboyNotes = self.tomboy.GetAllNotesWithTag("onthedesk")
        for noteID in tomboyNotes:
            self.notes[noteID] = VisualNote(self, noteID)
        self.linkNotes()
        
    
    def addChildNotes(self, note):
        for title in note.linkTitles:
            if not title in self.notes:
                self.addNote(title)
        # Link in the new note
        #note.linkNotes()
        # If there are any
        #for link in note.links:
        #    link.linkNotes()
        # We have to do a full re-linking because we have no idea what parents might pick up this note
        self.linkNotes()

    
    def linkNotes(self):
        for noteID, n in self.notes.iteritems():
            #print noteID, n
            n.makeLinks()
    
    def arrangeNotes(self):
        # need to split into isolated groups? - rootnode property could come in handy here
        
        # am doing this completely wrong! should be finding the average link POSITION! not total number of links!
        
        #gridX, gridY = 10, 10
        #print len(self.notes), math.sqrt( len(self.notes) )
        gridSize = int( math.sqrt( len(self.notes) ) )
        # Temp roundup fix?:
        gridSize += 1
        #print "grid", gridSize
        
        spacingX, spacingY = 200, 200
        
        #grid = []
        #line = []
        
        
        notes = self.notes.items()
        
        #for note in notes:
        #    
        
        grid = []
        
        
        ## Place notes into square grid - should we be sorting by popularity?
        
        # can't have two connected nodes in the same row. create new rows only on this basis?
        
        
        for y in range(0, gridSize):
            line = []
            for x in range(0, gridSize):
                if len(notes) > 0:
                    noteID, note = notes.pop()
                    note.x, note.y = x, y
                    line.append(note)
                    print noteID, note, note.x, note.y
            grid.append(line)
        
        #print grid
        
        # Work out the... for each note
        #for noteID, note in self.notes.iteritems():
        #    for l in note.links:
        
        """
        for line in grid:
            print "lenline", len(line)
            print "before",
            for l in line:
                print l.title,
            print
            line.sort()
            print "after ",
            for l in line:
                print l.title,  
            print
        """
        
        # Reapply to notes:
        for y, line in enumerate(grid):
            for x, note in enumerate(line):
                note.x = x * spacingX
                note.y = y * spacingY
        
        self.drawEnable = True
    
    def draw(self, dc):
        offset, scale = (0, 0), 1
        if self.drawEnable:
            for noteID, note in self.notes.iteritems():
                note.drawLinkLines(dc, offset, scale)
            
            for noteID, note in self.notes.iteritems():
                note.draw(dc, offset, scale)


class VisualNote():
    """Class for a visual note object"""
    def __init__(self, parent, noteID):
        self.parent = parent
        self.id = noteID
        
        self.loadContent()
        
        # depricate this (with growing algorithms etc)
        #w, h = self.Size
        w, h = 1000, 800
        self.x, self.y = random.randint(0, w), random.randint(0, h)
    
        self.fontSize = 20
        self.h, self.w = 10, 10
        self.border = 20
        self.roundingSize = 20
        self.linkOrbSize = 20

        self.drawSetup = False

    def __cmp__(self, other):
        #print "cmp", len(self.links), len(other.links), "=", cmp( len(self.links), len(other.links) )
        return cmp( len(self.links), len(other.links) )

    def loadContent(self):
        self.title = self.parent.tomboy.GetNoteTitle(self.id)
        self.text = self.parent.tomboy.GetNoteContents(self.id)
        self.xml = self.parent.tomboy.GetNoteCompleteXml(self.id)
        self.linkTitles = self.findLinks(self.xml)
        #self.makeLinks()   #can't do here as list is not complete yet

    def findLinks(self, text):
        """extracts links from tomboy xml e.g. #<link:internal>Hippy</link:internal>"""
        links = []
        remainText = text
        
        linkStart = remainText.find("<link:internal>") + 15
        linkEnd = remainText.find("</link:internal>")
        
        while linkStart >= 0 and linkEnd >=0:
            links.append( str( remainText[ linkStart:linkEnd ] ) )
            remainText = remainText[ linkEnd + 15: ]
            linkStart = remainText.find("<link:internal>") + 15
            linkEnd = remainText.find("</link:internal>")
        return links

    def makeLinks(self):
        self.links = []
        for noteID, note in self.parent.notes.iteritems():
            for title in self.linkTitles:
                if title == note.title:
                    self.links.append(note)

    def draw(self, dc, offset, scale):
        xo, yo = offset
        if not self.drawSetup:
            self.font = wx.Font(self.fontSize, wx.SWISS, wx.NORMAL, wx.NORMAL, False, u'Arial')
            dc.SetFont(self.font)
            self.textWidth, self.textHeight = dc.GetTextExtent(self.title)
            
            # set a cuttoff size, at which point we reduce font size
            sizeLimit = 200
            while self.textWidth > sizeLimit:
                self.fontSize -= 1
                self.font = wx.Font(self.fontSize, wx.SWISS, wx.NORMAL, wx.NORMAL, False, u'Arial')
                dc.SetFont(self.font)
                self.textWidth, self.textHeight = dc.GetTextExtent(self.title)
            
            self.w = self.textWidth + self.border
            self.h = self.textHeight + self.border
            self.drawSetup = True

        dc.SetPen(wx.Pen('#4c4c4c', 3, wx.SHORT_DASH))
        dc.SetBrush(wx.Brush('#539e47'))
        
        
        dc.DrawRoundedRectangleRect( (self.x * scale + xo, self.y * scale + yo, self.w * scale, self.h * scale), self.roundingSize * scale)
        dc.SetFont(self.font)
        dc.DrawText(self.title, (self.x + self.w / 2 - self.textWidth / 2) * scale + xo, (self.y + self.h / 2 - self.textHeight / 2) * scale + yo)
    
    def drawLinkLines(self, dc, offset, scale):
        xo, yo = offset
        for l in self.links:
            dx = l.x - self.x
            dy = l.y - self.y
            
            #temp fix
            self.linkRadius = self.w / 2
            # fix - divide by zero can occur in line below!!
            k = self.linkRadius / ( math.sqrt( math.pow( dx, 2 ) + math.pow( dy, 2 ) ) )
            cx = int( ( k * dx ) + self.x + xo )
            cy = int( ( k * dy ) + self.y + yo )
            
            dc.SetPen(wx.Pen('#6c6c6c', 3, wx.SHORT_DASH))
            dc.DrawLine( ( self.x + (self.w / 2) ) * scale + xo, ( self.y + (self.h / 2) ) * scale + yo, ( l.x + (l.w / 2) ) * scale + xo, ( l.y + (l.h / 2) ) * scale + yo)
            
            dc.SetPen(wx.Pen('#4c4c4c', 1, wx.TRANSPARENT))
            dc.SetBrush(wx.Brush('#d0dfff'))
            dc.DrawCircle( ( ( cx + (self.w / 2) ) * scale) + xo, (cy + (self.h / 2) * scale) + yo, self.linkOrbSize)
    
    def onMouseLeftDown(self, x, y):
        self.cursorOffsetX = self.x - x
        self.cursorOffsetY = self.y - y
        self.showText = True
    
    def onMouseLeftDClick(self, x, y):
        self.parent.tomboy.DisplayNote(self.id)
    
    def onMouseLeftUp(self, x, y):
        self.showText = False
    
    def move(self, pos):
        x, y = pos
        self.x, self.y = self.cursorOffsetX + x, self.cursorOffsetY + y



# Display the Start Here note
#tomboy.DisplayNote(tomboy.FindStartHereNote())

# Display the title of every note
#for n in tomboy.ListAllNotes():
#	print tomboy.GetNoteTitle(n)

# Display the contents of the note called Test
#print tomboy.GetNoteContents(tomboy.FindNote("Todo Today"))

# Add a tag to the note called Test
#tomboy.AddTagToNote(tomboy.FindNote("Todo Today"), "onthedesk")
#tomboy.AddTagToNote(tomboy.FindNote("People:"), "onthedesk")
#tomboy.AddTagToNote(tomboy.FindNote("Music:"), "onthedesk")
#tomboy.AddTagToNote(tomboy.FindNote("[Master Index]"), "onthedesk")



# Print the XML data for the note called Test
#print tomboy.GetNoteCompleteXml(tomboy.FindNote("Todo Today"))


# should move some stuff to creation of draw canvas and note entity, as re are repeating a lot!
#font = wx.Font(20, wx.MODERN, wx.NORMAL, wx.NORMAL)

# font type: wx.DEFAULT, wx.DECORATIVE, wx.ROMAN, wx.SCRIPT, wx.SWISS, wx.MODERN
# slant: wx.NORMAL, wx.SLANT or wx.ITALIC
# weight: wx.NORMAL, wx.LIGHT or wx.BOLD
#font1 = wx.Font(10, wx.SWISS, wx.ITALIC, wx.NORMAL)
